package com.feinno.urcs.group.servlet;

import com.feinno.msrp.MsrpSession;
import com.feinno.sip.header.From;
import com.feinno.sip.header.SIPHeader;
import com.feinno.sip.header.Supported;
import com.feinno.sip.header.extensions.AcceptContact;
import com.feinno.sip.message.Content;
import com.feinno.sip.provider.MessageFactoryImpl;
import com.feinno.urcs.content.MimeType;
import com.feinno.urcs.content.Sdp;
import com.feinno.urcs.content.UrcsContent;
import com.feinno.urcs.group.GroupConstants;
import com.feinno.urcs.group.api.GroupChatService;
import com.feinno.urcs.group.api.GroupIndexService;
import com.feinno.urcs.group.entity.GroupFileInfo;
import com.feinno.urcs.group.entity.GroupIndex;
import com.feinno.urcs.group.entity.GroupMessageType;
import com.feinno.urcs.group.siputils.GroupHeaderUtils;
import com.feinno.urcs.group.siputils.MsrpUtils;
import com.feinno.urcs.group.siputils.URIUtils;
import com.feinno.urcs.sipservlet.FileTransferServlet;
import com.feinno.urcs.sipservlet.SipServletRequest;
import com.feinno.urcs.sipservlet.msrp.MsrpSessionFactory;
import com.feinno.urcs.sipservlet.utils.FileAttribute;
import com.feinno.urcs.sipservlet.utils.HotFileOutputStream;
import com.feinno.urcs.storage.FileStream;
import com.feinno.urcs.storage.FileStreamService;
import com.feinno.urcs.types.MobileNo;
import com.feinno.util.DateUtil;
import com.feinno.util.StringUtils;
import org.helium.framework.annotations.ServiceSetter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sdp.SdpException;
import javax.sdp.SessionDescription;
import javax.sip.header.Header;
import javax.sip.header.SupportedHeader;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;


/**
 * Created by liufeng on 2015/5/13.
 */
public class GroupFileTransferServlet extends FileTransferServlet {

	private static final Logger LOGGER = LoggerFactory.getLogger(GroupFileTransferServlet.class);
	@ServiceSetter
	private MsrpSessionFactory msrpFactory;
	@ServiceSetter
	private GroupChatService groupChatService;
	@ServiceSetter
	private GroupIndexService groupIndexService;
	@ServiceSetter
	private FileStreamService fileStreamService;
	private String OUTPUT_KEY = "GROUP_FILE_STORAGE_KEY";
	/**
	 * 上传文件功能(包含断点续传)
	 *
	 * @param request
	 * @return
	 */
	@Override
	protected OutputStream getOutputStream(SipServletRequest request) {
		LOGGER.info("CreateOutputStream:{}", request);
		FileStream fileStream = null;
		//传如参数较多需解析Request两次
		try {
			GroupFileInfo fileInfo = getGroupFileInfo(request);
			String fileId = getHotFileId(request);
			//设置断点续传位置
			if (fileInfo != null && fileInfo.getFileRangeBegin() > 1) {
				//文件断点续传
				fileStream = fileStreamService.get(fileInfo.getTransferId());
				fileStream.seekOutputSteam(fileInfo.getFileRangeBegin() - 1);
			} else if (fileId != null) {
				//支持HotFile
				return HotFileOutputStream.getDefault();
			} else {
				//正常文件传输
				fileStream = fileStreamService.get(fileInfo.getTransferId());
				fileStream.setFileName(fileInfo.getFileName());
				fileStream.setFileType(fileInfo.getFileType());
				fileStream.setFileSize(fileInfo.getFileSize());
				fileStream.flush();
			}
			//支持hotfile
			SupportedHeader supportedHeader = (SupportedHeader) MessageFactoryImpl.getInstance().getHeaderFactory().
					createSupportedHeader("100rel,209file");
			request.setHeader(supportedHeader);

			Header hotFileHeader = MessageFactoryImpl.getInstance().getHeaderFactory().createHeader("Hot-File",
					fileStream.getFileId());
			request.setHeader(hotFileHeader);

		} catch (Exception e) {
			LOGGER.error("Create FileOutPutStream Error.", e);
		}
		request.getSession().put(OUTPUT_KEY, fileStream);
		return fileStream.getOutputSteam();
	}

	/**
	 * 下载文件(包含断点续接)
	 *
	 * @param request
	 * @return
	 */
	@Override
	protected MsrpSession createMsrpSession(SipServletRequest request) {

		LOGGER.info("createMsrpSession:{}", request);
		return msrpFactory.createSession();
	}

	/**
	 * msrp消息接受完成后触发
	 *
	 * @param event
	 */
	@Override
	protected void event(Event event) {
		LOGGER.info("MSRP END Event.{}", event);
		//只拉取文件
		if (!this.isPull(event.getInviteReuqest())) {
			return;
		}
		if (event.getState() == State.SUCCESS) {
			LOGGER.info("Receive MsrpData Success. {}", event.getInviteReuqest().toString());
			this.receiveDone(event.getInviteReuqest());
		} else if (event.getState() == State.FAILED) {
			LOGGER.error("Receive MsrpData Fail Error. {}", event.getError().getMessage());
		}
	}

	/**
	 * 接受msrp完成后，处理下行任务
	 */
	private void receiveDone(SipServletRequest inviteRequest) {
		try {
			String requestUri = inviteRequest.getRequestURI().toString();
			GroupIndex groupIndex = groupIndexService.getGroupByUri(requestUri);
			GroupFileInfo groupFileInfo = getGroupFileInfo(inviteRequest);
			if (groupFileInfo.getMessageType() == GroupMessageType.IMG ||
					groupFileInfo.getMessageType() == GroupMessageType.CARD ||
					groupFileInfo.getMessageType() == GroupMessageType.AUDIO ||
					groupFileInfo.getMessageType() == GroupMessageType.VIDEO) {
			}
			String fromMobileNo = URIUtils.getMobileNo(GroupHeaderUtils.getFromUriByPAssertedIdentity(inviteRequest));
			if (StringUtils.isNullOrEmpty(fromMobileNo)) {
				From fromHeader = (From) inviteRequest.getHeader(From.NAME);
				if (fromHeader != null) {
					fromMobileNo = URIUtils.getMobileNo(fromHeader.getAddress().getURI());
				}
			}
			groupChatService.sendFile(groupIndex.getGroupId(), MobileNo.parseFrom(fromMobileNo), groupFileInfo, DateUtil.getUTCNow());
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	private GroupFileInfo getGroupFileInfo(SipServletRequest inviteRequest) throws Exception {
		GroupFileInfo retval = new GroupFileInfo();
		GroupMessageType messageType = GroupMessageType.FILE;
		Sdp sdp = inviteRequest.getMultipartMimeContent().getContent(Sdp.class);
		SessionDescription sessionDescription = sdp.getSdp();
		retval.setAcceptType(MsrpUtils.getAttribute(sessionDescription, "accept-types"));
		retval.setAcceptWrappedType(MsrpUtils.getMsrpAcceptWrappedType(sessionDescription));
		retval.setSendonly(true);
		retval.setRecvonly(false);
		retval.setTransferId(MsrpUtils.getAttribute(sessionDescription, "file-transfer-id"));
		String timelen = MsrpUtils.getAttribute(sessionDescription, "file-disposition");
		if (!StringUtils.isNullOrEmpty(timelen)) {
			retval.setTimelen(Integer.parseInt(timelen.split("=")[1]));
		}
		AcceptContact ac = (AcceptContact) inviteRequest.getHeader(AcceptContact.NAME);
		String fileSelector = MsrpUtils.getAttribute(sessionDescription, "file-selector");
		String[] fileDesribe = fileSelector.split(" ");
		for (String description : fileDesribe) {
			String[] pairStrings = description.split(":");
			if (pairStrings[0].equalsIgnoreCase("name")) {
				retval.setFileName(pairStrings[1].replace("\"", ""));
			} else if (pairStrings[0].equalsIgnoreCase("size")) {
				retval.setFileSize(Integer.parseInt(pairStrings[1]));
			} else if (pairStrings[0].equalsIgnoreCase("type")) {
				retval.setFileType(pairStrings[1]);
			}
		}
		String fileName = retval.getFileName();
		String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1);
		if (fileSuffix.equalsIgnoreCase("vcf")) {
			messageType = GroupMessageType.CARD;            //electronic business card
		}
		if (!StringUtils.isNullOrEmpty(retval.getAcceptType()) && retval.getAcceptType().equalsIgnoreCase("application/vnd.gsma.rcspushlocation+xml")) {
			messageType = GroupMessageType.LOCATION;        //geographical location
		}
		MimeType.parse(fileSuffix);
		List<String> thumbnailTypeList = new ArrayList<String>();
		thumbnailTypeList.add(MimeType.ImageJpeg.getValue());
		thumbnailTypeList.add(MimeType.ImageGif.getValue());
		thumbnailTypeList.add(MimeType.ImageBmp.getValue());
		thumbnailTypeList.add(MimeType.ImagePng.getValue());
		String tmpFileSuffix = fileSuffix.toLowerCase();
		if(tmpFileSuffix.equals("jpg") || tmpFileSuffix.equals("jpeg")|| tmpFileSuffix.equals("gif")|| tmpFileSuffix.equals("bmp")|| tmpFileSuffix.equals("png")){
			messageType =GroupMessageType.IMG;
		}
		Iterator<Content> iterator = inviteRequest.getMultipartMimeContent().getContents();
		while (iterator.hasNext()) {
			Content content = iterator.next();
			String contentType = content.getContentTypeHeader().getContentType() + "/" + content.getContentTypeHeader().getContentSubType();
			if (thumbnailTypeList.contains(contentType)) {
				try {
					UrcsContent tmp = (UrcsContent) content;
					if (tmp.getHeaders() != null && tmp.getHeaders().size() > 0) {
						tmp.getHeaders().forEach(header -> {
							if (header != null && header.getHeaderName().toLowerCase().equals(GroupConstants.HEADER_CONTENT_TRANSFER_ENCODING.toLowerCase())) {
								retval.setContentTransferEncoding(header.getHeaderValue());
							}
						});
					}
				} catch (Exception e) {
					LOGGER.warn("UrcsContent headerMap is null", e);
				}
				retval.setThumbnail(content.getContent());   //add thumbnail
			}
			if (contentType.equalsIgnoreCase(MimeType.CPIM.getValue())) {
				retval.setStatusReport(content.getContent());   //status report
			}
		}
		retval.setFileRangeEnd(retval.getFileSize());
		retval.setMessageType(messageType);
		String hotFileId = getHotFileId(inviteRequest);
		if (hotFileId != null) {
			retval.setFileId(hotFileId);
			retval.setTransferId(hotFileId);
		}else {
			retval.setFileId(retval.getTransferId());
		}
		return retval;
	}

	/**
	 * Parse HotFileId From Request
	 *
	 * @param request
	 * @return
	 */
	public static String getHotFileId(SipServletRequest request) throws SdpException, ParseException {
		String fileId = null;
		//get hot file id
		ListIterator<SIPHeader> supportSipHeaders = request.getHeaders(Supported.NAME);
		while (supportSipHeaders.hasNext()) {
			SIPHeader sipHeader = supportSipHeaders.next();
			if (sipHeader.getHeaderValue().toLowerCase().indexOf("209file") >= 0) {
				SIPHeader header = (SIPHeader) request.getHeader("Hot-File");
				fileId = header.getHeaderValue();
			}
		}
		return fileId;
	}

	@Override
	protected FileStreamInfo getInputStream(SipServletRequest request) {
		LOGGER.info("getInputStream:{}", request);
		InputStream inputStream = null;
		FileAttribute fileAttr = null;
		FileStreamInfo info = null;
		try {
			fileAttr = FileAttribute.create(request);
			FileStream fileStream = fileStreamService.get(fileAttr.getTransferId());
			//不支持filerange
			if (fileAttr.getFileRange() == null) {
				fileAttr.setFileRange("1-" + fileStream.getFileSize());
			}
			//文件断点续接
			if (fileAttr != null && fileAttr.getFileRangeBegin() > 1 && fileStream != null) {
				fileStream.seekInputStream(fileAttr.getFileRangeBegin() - 1);
			}
			inputStream = fileStream.getInputStream();
			info = FileStreamInfo.create(fileAttr, inputStream);
		} catch (Exception e) {
			LOGGER.info("Get InputStream Error.{}", e);
		}
		return info;
	}
}